package anneau;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.ejb.LocalBean;
import javax.ejb.Stateful;
import javax.ejb.StatefulTimeout;

import service.Fichier;


/**
 * Session Bean implementation class Noeud_Bean
 */
@Stateful(name = "Noeud_Bean")
@StatefulTimeout(unit = java.util.concurrent.TimeUnit.MINUTES, value = -1)
@LocalBean
public class Noeud_Bean implements Noeud_ITF {
	// ATTRIBUTS
	private UUID uuid;
	private Noeud_ITF precedent;
	private Noeud_ITF suivant;
	private List<Fichier> liste_fichiers;
	private String adresse_ip;
	private int port;
	
	
	// CONSTRUCTEUR
	public Noeud_Bean() {
		this.uuid = UUID.randomUUID();
        this.precedent = null;
        this.suivant = null;
        this.liste_fichiers = new ArrayList<Fichier>();
        this.adresse_ip = null;
        this.port = 0;
    }
	
    
	// ACCESSEURS
	@Override
	public UUID getUuid() { return this.uuid; }
	
    @Override
    public Noeud_ITF getPrecedent() { return this.precedent; }

    @Override
    public Noeud_ITF getSuivant() { return this.suivant; }

    @Override
    public void setPrecedent(Noeud_ITF precedent) { this.precedent = precedent; }

    @Override
    public void setSuivant(Noeud_ITF suivant) { this.suivant = suivant; }
    
    @Override
    public void setListeFichiers(List<Fichier> liste_fichiers) { this.liste_fichiers = liste_fichiers; }
    
    @Override
    public void setAdresseIp(String adresse_ip) { this.adresse_ip = adresse_ip; }
    
    @Override
    public void setPort(int port) { this.port = port; }
    
    
    // METHODES
	@Override
    public Map<Fichier, List<UUID>> getFichiers(UUID initiateur, Map<Fichier, List<UUID>> map_fichiers) {
		System.out.println("Noeud_Bean.getFichiers");
    	if(!this.uuid.equals(initiateur)) {
    		System.out.println("1");
    		// Pour chaque Fichier que possede le client
    		for(Fichier fichier_tmp : this.liste_fichiers) {
    			System.out.println("2");
    			// On recupere, si elle existe, la liste des Noeud possedant ce Fichier
    			List<UUID> list_noeud_tmp = map_fichiers.get(fichier_tmp);
    			System.out.println("3");
    			// Si la liste des Noeud existe et que le Noeud courant (this) n'y est pas
    			if(list_noeud_tmp != null && !list_noeud_tmp.contains(this.uuid)) {
    				System.out.println("4");
    				// On ajoute le Noeud courant (this) a la liste des Noeud possedant ce Fichier
    				list_noeud_tmp.add(this.uuid);
    				map_fichiers.put(fichier_tmp, list_noeud_tmp);
    			}
    			// Si le Noeud courant (this) n'est pas encore indique comme possedant le Fichier
    			else {
    				System.out.println("5");
    				if(list_noeud_tmp == null) {
    					list_noeud_tmp = new ArrayList<UUID>();
    				}
    				// On ajoute le Noeud courant (this) a la liste des Noeud possedant ce fichier
    				list_noeud_tmp.add(this.uuid);
    				// Et on ajoute le Fichier a la liste des Fichier disponibles
    				map_fichiers.put(fichier_tmp, list_noeud_tmp);
    			}
    		}
    		
    		if(!this.suivant.getUuid().equals(initiateur)) {
    			System.out.println("6");
    			// On transmet le message au Noeud suivant
    			return this.suivant.getFichiers(initiateur, map_fichiers);
    		}
    	}
    	else {
    		System.out.println("Noeud_Bean.getFichiers a fait le tour de l'anneau.");
    		System.out.println(map_fichiers);
    	}

		return map_fichiers;
    }
    
    @Override
	public String[] getFichier(UUID initiateur, String md5) {
    	System.out.println("Noeud_Bean.getFichier(" + initiateur.toString() + ", " + md5 + ")");
    	System.out.println("this.uuid = " + this.uuid.toString());
    	if(!this.uuid.equals(initiateur)) {
    		// Pour chaque Fichier que possede le client
    		for(Fichier fichier_tmp : this.liste_fichiers) {
    			// Si on possede le Fichier demande
    			if(fichier_tmp.getMd5().equals(md5)) {
    				// On renvoie l'adresse IP du Noeud courant
    				String[] adresse_ip_port = new String[2];
    				adresse_ip_port[0] = this.adresse_ip;
    				adresse_ip_port[1] = Integer.toString(this.port);
    				return adresse_ip_port;
    			}
    		}
    		
    		if(!this.suivant.getUuid().equals(initiateur)) {
    			System.out.println("On transmet le message au Noeud suivant.");
    			// On transmet le message au Noeud suivant
    			return this.suivant.getFichier(initiateur, md5);
    		}
    	}
    	else {
    		System.out.println("Noeud_Bean.getFichier a fait le tour de l'anneau.");
    	}
    	
		return null;
	}
    
    @Override
    public List<Fichier> getAllFichiersClient() {
    	List<Fichier> fichiers = new ArrayList<Fichier>();
    	Map<Fichier, List<UUID>> liste_fichiers_noeuds = this.suivant.getFichiers(this.uuid, new HashMap<Fichier, List<UUID>>());
    	Set<Fichier> set = liste_fichiers_noeuds.keySet();
    	Iterator<Fichier> i = set.iterator();
    	while(i.hasNext()) {
    		fichiers.add((Fichier) i.next());
    	}
    	
    	return fichiers;
    }
    
    @Override
    public String[] getFichierClient(String md5) {
    	return this.suivant.getFichier(this.getUuid(), md5);
    }
    
    @Override
    public boolean supprimerFichier(String nomFichier) {
    	
    	for (Fichier fichier : liste_fichiers) {
    		if (fichier.getNomFichier().equals(nomFichier)) {
    			liste_fichiers.remove(fichier);
    			return true;
    		}
    	}
    	
    	return false;
    }
    
	@Override
	public String heartBeat() {
		return "Je suis vivant !";
	}
	
	@Override
	public boolean equals(Object noeud) {
		if(noeud != null) {
			if(!this.uuid.equals(((Noeud_ITF)noeud).getUuid())) {
				return true;
			}
		}
		return false;
	}
}
